package HTMLParser;
import Parser.*;

/*******************************************************************************
 * Creates a lexical analyser that will analyses a stream of characters,
 * splitting it into tokens of different types.
 * @author Tudor Pascu
 * @version FINAL
 *******************************************************************************/
public class HTMLLexicalAnalyser extends LexicalAnalyser
{
    private Token token;
    private String tokenString;
    private String typeString;
    private char current;//holds the character currently being analysed.
    private static final String CLOSE_TAG = "CLOSE";
    private static final String OPEN_TAG = "OPEN";
    private static final String SELF_CLOSE_TAG = "SELF_CLOSE";
    private static final String TEXT = "TEXT";
    private static final String COMMENT = "COMMENT";
    private String[] entities = {"&amp;","&gt;","&lt;","&quot;"};
    private String[] entitiesTranslated = {"&",">","<","\""};

    /***************************************************************************
     * Creates an HTMLLexicalAnalyser object that will analyse a stream of
     * characters.
     * @param address Address of the file to be read.
     ***************************************************************************/
    public HTMLLexicalAnalyser(String address)
    {
        super(address);
        current = file.getCharacter();
    }

    /***************************************************************************
     * Returns a token object.
     * @return Token object.
     ***************************************************************************/
    public Token getToken()
    {
        tokenString = "";
        typeString = "";
        if(file.hasCharacter()){
            if(current == '<'){
                tag();//puts the contents of a tag into the tokenString.
                checkTagType();//checks if the tag is of type OPEN, CLOSE or SELF_CLOSE removing any "/".
                //If a tag is a comment, it will be ignored.
                if(isComment()){
                    tokenString = "";
                    typeString = COMMENT;
                }
            }else{
                text();//puts text into the tokenString.
                checkForEntities();
            }
        }
        token = new Token(tokenString, typeString);
        return token;
    }

    /***************************************************************************
     * Checks for entities and replaces them with the corresponding symbols.
     ***************************************************************************/
    public void checkForEntities()
    {
        for(int i = 0; i < tokenString.length(); i++){
            if(tokenString.charAt(i) == '&')
            {
                for(int j = 0; j < entities.length; j++){
                    if(i + entities[j].length() < tokenString.length()){
                        if(tokenString.substring(i, i + entities[j].length()).equals(entities[j])){
                            tokenString = tokenString.substring(0, i) + entitiesTranslated[j] + tokenString.substring(i + entities[j].length());
                        }
                    }
                }
            }
        }
    }

    /***************************************************************************
     * Puts text into the tokenString and sets the tokenType to TEXT.
     ***************************************************************************/
    private void text()
    {
        while(current != '<' && file.hasCharacter()){
            tokenString = tokenString + current;
            current = file.getCharacter();
        }
        if(file.hasCharacter() == false){
            tokenString = tokenString + current;
        }
        typeString = TEXT;
    }

    /***************************************************************************
     * Puts the contents of a tag into the tokenString.
     ***************************************************************************/
    private void tag()
    {
        current = file.getCharacter();
        while(current != '>' && file.hasCharacter()){
            tokenString = tokenString + current;
            current = file.getCharacter();
        }
        if(file.hasCharacter()){
            current = file.getCharacter();
        }
    }

    /***************************************************************************
     * Checks if the tag is of type OPEN, CLOSE or SELF_CLOSE removing any "/".
     ***************************************************************************/
    private void checkTagType()
    {
        if(tokenString.toLowerCase().equals("br") || tokenString.toLowerCase().contains("img src=")){
            typeString = SELF_CLOSE_TAG;
        }else if(tokenString.charAt(0) == '/'){
            typeString = CLOSE_TAG;
            tokenString = tokenString.substring(1, tokenString.length());
        }else if(tokenString.charAt(tokenString.length() - 1) == '/'){
            typeString = SELF_CLOSE_TAG;
            tokenString = tokenString.substring(0, tokenString.length() - 1);
        }else{
            typeString = OPEN_TAG;
        }
    }

    /***************************************************************************
     * Returns true if a tag is a comment false otherwise.
     * @return True if a tag is a comment false otherwise.
     ***************************************************************************/
    private boolean isComment()
    {
        if(tokenString.length() > 4){
            if(tokenString.substring(0, 3).equals("!--") && tokenString.substring(tokenString.length() - 2, tokenString.length()).equals("--")){
                return true;
            }
        }
        return false;
    }

    /***************************************************************************
     * Returns true if any more tokens are to be returned , false otherwise.
     * @return True if any more tokens are to be returned , false otherwise.
     ***************************************************************************/
    public boolean hasToken()
    {
        return file.hasCharacter();
    }
}